Josh Sutphin
GamesMusicWriting         

Legacy of the Elder Star

Kickbomb Entertainment | Founder | March 2013 - June 2016

Legacy of the Elder Star is a side-scrolling shoot-em-up with a twist: using a one-handed, mouse-driven control scheme, you'll dodge and strike with 1:1 precision and unlimited movement speed. Evade intense bullet patterns in the blink of an eye, then dash through entire enemy squads to crush them in a single gesture. Movement is everything in Legacy of the Elder Star, and no other shoot 'em up moves like this.

Development overview

A screenshot from Legacy of the Elder Star, showing the Cosmonaut star-dashing through a huge explosion, against a backdrop of a blue-and-orange alien world.

This was my first major indie title built for commercial release. It was entirely self-funded, self-directed, and self-published. I did all the design, programming, music, and UI, and worked with local artist Erik Exeter to produce the art style, game assets, and animations.

The game is built in Unity and shipped on Unity 5.4. I used 2D Toolkit for in-game sprites and UI, and Spine for character and environment animations. Steamworks.NET provided Steam API support with which I integrated leaderboards and achievements. I also wrote extensive custom utilities and editor extensions for object pooling, visual level scripting, sequencing effects, and mixing audio, among other things.

Throughout development I produced several trailers which I scripted, shot, edited, and scored, including the launch trailer shown above.

Soundtrack

For this game, I wrote a driving melodic electro-rock soundtrack, evoking and modernizing the chiptune style of old-school arcade shoot 'em ups. I put a lot of emphasis here on developing, reprising, and interweaving musical themes.

"I have to start with praise for the music of Elder Star. Props to the composer for writing something that's at once epic, spacey and robotic that evokes the classic 8/16-bit legends."
Steam review by PapaBrain

Accolades

A screenshot from Legacy of the Elder Star, showing a carrier and two jetpack soldiers targeting the Cosmonaut with missiles, against a seafoam-colored sky.

"Legacy of the Elder Star knocks it out of the park, retaining the retro charm of the genre without shackling itself to the past."
— GamerPros.co

"[The dash is] a great mechanic, that allows for a fresh new take on an age old genre and makes for an intense and thoroughly enjoyable shmup experience."
— Alpha Beta Gamer

"The game runs like heaven, and controls wonderfully."
— Enemy Slime

"Fans of the genre should definitely be checking this game out."
— True PC Gaming

A screenshot from Legacy of the Elder Star, showing an octopus-like robot boss deploying seeker drones, nestled in bright red-orange clouds in a toxic green sky.

"Has an incredibly holistic design that completely understands how shmups can benefit from being designed centrally for the PC instead of being mere ports of arcade games... In both design and execution, the game has very few peers."
Steam review by Owen Ketillson

"Fascinating, 1:1 mouse control is something we don't see often in shmups, but there may be something we're missing there since it feels super fluid and accessible in this game."
Steam review by Structor

"Simple. Pleasant. Hard. Loveable."
Steam review by HappyLarry

"This game has accessibility options out the ass. Colorblind? There's a toggle. Autism? Toggles for slowing it down (or speed it up) and reducing flashes / shakes. One handed? You can play with just a mouse. On top of all that it's free so if you're poor you can afford it. Great for kids too because if you die you can just hit continue (no permadeath as far as I could see.)"
Steam review by Scary Guy

Press coverage

How to get it

Legacy of the Elder Star can be downloaded for free from itch.io and Steam.

Development techniques

Here are some noteworthy techniques and implementation details that went into this project.

Object pooling

Shoot-em-ups spawn enemies and bullets (especially bullets) at a terrifying rate. Unity's default Instantiate() call is pretty heavy and becomes a CPU performance bottleneck for this use case, so I wrote an object pooling system to take care of it.

The Recycler class provides public API replacements for Instantiate and Destroy which manage pooling automatically and transparently. The Recycler maintains a dictionary of object pools: the key is a prefab, and the value is a list of disabled instances of that prefab. When I instantiate a prefab, the Recycler pops one of these instances, enables it, and returns it as the newly "instantiated" instance. If the pool is empty, a new instance is created on-the-fly in the normal "heavyweight" way.

Since those on-the-fly allocations are heavy, the Recycler also provides a Preallocate call which allows me to pre-fill the pool with a specified number of instances of each prefab type. I do this under the guise of a load screen. The Recycler's custom inspector provides runtime pool counts in an easily-readable format; I used that to estimate good initial pool counts for preallocation. (The on-the-fly allocation is really just a safeguard; in practice it's almost never hit.)

When an object is destroyed via the Recycler API, it's simply disabled and popped back onto its pool.

With appropriate preallocation -- which is time-sliced so the load screen can continue to animate during this process, despite object instantiations being required to run on the main thread -- the Recycler is capable of spawning upwards of 10,000 bullets per second with minimal performance impact. In practice, the game never gets quite that hectic, so there's plenty of performance headroom to work with.

Level scripting

I created a graphical editor for visually laying out the sequence of events in each level. This allowed for easy rapid iteration on level progressions.

Screenshot of the level sequence editor, showing the editing of a single event

With this tool I could quickly place different event types -- play music, show HUD messages, enemy spawn sequences, boss encounters, etc. -- and adjust their timing. The level could start at any event, so testing later portions of the level was as easy as double-clicking the event of interest to mark it as the new (temporary) starting point, and hitting Play.

Events could also execute in parallel by disabling the Block? settings. This was useful for things like triggering a HUD message with a slightly-delayed, but overlapping, boss arrival. I didn't use this often, but it came in really handy for those cases where it was needed.

The core campaign levels had linear event sequences, but the daily challenges used a randomized non-linear sequence, which the tool also supported:

Screenshot of the level sequence editor, showing the arrangement of a set of events

In this case, any event with multiple outgoing connections would choose one of those connections at random each time it finished executing. Combining that with a looping setup provided randomly-generated event sequences at virtually no cost. The daily challenges simply injected a random seed -- based on the current date -- when the level sequence initialized, ensuring the same sequence was generated for every run that day.

Custom audio mixer

I started work on Legacy of the Elder Star during the 3.x release cycle, long before Unity added their native Audio Mixer, which meant the only audio implementation available to me out of the box was adding AudioSource components to everything. That's fine as it goes, but it makes mixing a pain because the mix controls for your sounds are scattered all over your project, buried in scenes and prefabs. I wanted a cleaner way to work with audio, so I wrote a simple custom audio mixer.

A screenshot of the custom audio mixer interface

You'll see a Mixer Group property in the screenshot; that was added after upgrading to the 5.x release cycle to integrate with the native Audio Mixer, where I combined groups of sound events into buses like "Weapons", "Explosions", and "Interface", further simplifying mixing.

This worked a bit like a stripped-down version of FMOD: I would create named sound events, and invoke them in code using that name instead of an asset reference. The sound event took care of random clip variation, simultaneous voice limiting, and ducking. Each sound event had its own volume slider, all accessible right from the AudioMixer custom inspector UI, which made final mixdown a breeze. Because there were many sound events, I didn't list them in a big array, but instead created the Sound Event dropdown you can see in the screenshot, from which you could pick which sound event to edit, with the rest of the UI showing editing controls for just that sound event.

Lessons learned

This was my first completely independent commercial release, which meant I had to learn how to start and run a business: Kickbomb Entertainment. After a decade working for other people's studios, it was extremely enlightening -- and at times challenging -- to see the view from the other side of the table. That business lasted four years, and while it's now shuttered, it remains one of the proudest achievements of my professional life.

As it turns out, marketing is hard, and is a completely different skill set from development. I underestimated both the importance and difficulty of that aspect of the product development pipeline. I made mistakes and tried new things, and while ultimately the game's market penetration still fell short of expectations, I came out the other side with a much clearer and more practical understanding of the state of the industry and how rapidly things have been changing.

Created 11/12/2022 • Updated 11/30/2023